#include <iostream>    
#include <fstream>
#include <cerrno>
#include <vector>
#include <string>

extern "C" {
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <fcntl.h>
}

using namespace std;

int childnum = 5;

int forkhandle_read_write(const int type, const char* file);
int test_read_write(const int type, const char* file);

int main(int argc, char **argv)
{
	string file = "";
	bool help = false;
	bool fileflag = false;
	bool write = false;
	bool read = false;
	char optchar;
	struct stat statInfo;

	while ((optchar = getopt(argc, argv, "rwhf:c:")) != -1) {
		switch (optchar) {
			case 'f':
				file = optarg;
				fileflag = true;
				cout << "workfile:" << file <<endl;
				break;
			case 'h':
				help = true;
				break;
			case 'r':
				read = true;
				break;
			case 'w':
				write = true;
				break;
			case 'c':
				childnum = atoi(optarg);
				cout << "childnum:" << childnum <<endl;
				break;
			default:
				cout << "Unrecognized flag " << optchar << endl;
				help = true;
				break;
		}
	}

	if (help || !fileflag) {
		cout << "Usage: " << argv[0] << "[-r|-w|-c|-f] "
			<< "  -r:read; -w:append write; -c: child process number; "
			<< " -f:file"
			<< endl;
		exit(0);
	}

	struct timeval begin_time;
	struct timeval end_time;
	float timeuse;

	gettimeofday(&begin_time, NULL);

	if (write)	
	{
		forkhandle_read_write(2, file.c_str());
	}

	if (read)	
	{
		forkhandle_read_write(1, file.c_str());
	}

	gettimeofday(&end_time, NULL);
	timeuse = 1000000 * (end_time.tv_sec - begin_time.tv_sec) +
		end_time.tv_usec - begin_time.tv_usec;
	cout << "spent " << timeuse/1000000 << "s" <<endl;

	fflush(stdout);
	return 0;
}

//type:1,read; 2:write
int forkhandle_read_write(const int type, const char* file)
{
	int i;
	pid_t pid;

	vector<pid_t> vec_pid;

	for(i = 0; i < childnum; i++)
	{
		pid = fork();		
		if (-1 == pid)
		{
			cout << "failed: fork faild, child[" << i << "]\n";
		}
		else if(0 == pid)
		{
			cout << "fork succeed, child[" << i << "]\n";
			test_read_write(type, file);
			exit(0);
		}
		else
		{
			vec_pid.push_back(pid);
		}
	}

	//parent handle singal
	int size = vec_pid.size();
	for (i = 0; i < size; i++)
	{
		pid = waitpid(vec_pid[i], NULL, 0);	
		cout << "wait " << i+1 << "child[" << vec_pid[i] << "] result[" << pid << "]" << endl; 
	}

	return 0;
}


int test_read_write(const int type, const char* file) 
{
	int res;

	if (NULL == file)
	{
		cout << "file is null" << endl;
		return -1;
	}


	int i;
	int fd;
	pid_t mypid = getpid();

	//read
	if (type == 1)
	{
		char buf[17] = {'\0'};
		int len = sizeof(buf) - 1;
		if ( (fd = open(file,  O_RDONLY) ) < 0) 
		{
			printf("child[%d] open file [%s] failed\n", mypid, file);
			return -1;
		}

		for (i = 0; i < 5; i++)
		{
			printf("child[%d]-[%d] read begin\n", mypid, i);
			while( read(fd, buf, len) > 0)
			{
				printf("child[%d]-[%d]:str[%s] \n", mypid, i, buf);
			}
			
			lseek(fd, 0, SEEK_SET);
		}
		close(fd);
		printf("child[%d] read file [%s] ok\n", mypid, file);
	}
	else if (type == 2)   //write
	{
		if ( (fd = open(file, O_WRONLY|O_APPEND) ) < 0) 
		{
			printf("child[%d] open file [%s] failed\n", mypid, file);
			return -1;
		}
	
		char buf[16] = {'\0'};
		
		for (i = 0; i < 5; i++)
		{
			sprintf(buf, "child[%d]-[%d]write file----\n", mypid, i);
			sleep(1);
			write(fd, buf, strlen(buf));
		}
		close(fd);

		printf("child[%d] write-append file [%s] ok\n", mypid, file);
	}

	return 0;
}
